﻿#include "tcp_connection.hh"

#include <iostream>

// Dummy implementation of a TCP connection

// For Lab 4, please replace with a real implementation that passes the
// automated checks run by `make check`.

template <typename... Targs>
void DUMMY_CODE(Targs &&... /* unused */) {}

using namespace std;

size_t TCPConnection::remaining_outbound_capacity() const { return _sender.stream_in().remaining_capacity(); }

size_t TCPConnection::bytes_in_flight() const { return _sender.bytes_in_flight(); }

size_t TCPConnection::unassembled_bytes() const { return _receiver.unassembled_bytes(); }

size_t TCPConnection::time_since_last_segment_received() const { return _time_since_last_segment_received; }

void TCPConnection::segment_received(const TCPSegment &seg) {
    _time_since_last_segment_received = 0;
    TCPHeader header = seg.header();
    if (header.rst) {
        _receiver.stream_out().set_error();
        _sender.stream_in().set_error();
        return;
    }
    // refuse the data without ack
    if (!header.ack && (_receiver.ackno().has_value() || !header.syn))
        return;

    // bad ACKs in SYN_SENT should be ignored
    if (_sender.next_seqno_absolute() == _sender.bytes_in_flight() && _sender.next_seqno_absolute() > 0 &&
        header.ackno != _sender.next_seqno() && !header.syn) {
        return;
    }

    bool send_empty = false;
    bool rec_valid = _receiver.segment_received(seg);
    if (!rec_valid) {
        send_empty = true;
    }
    // hasn't syn and header with syn
    if (_sender.next_seqno_absolute() == 0) {
        if (header.syn) {
            connect();
        }
        return;
    }

    bool ack_valid = _sender.ack_received(header.ackno, header.win);
    if (!ack_valid) {
        send_empty = true;
    }

    if (seg.length_in_sequence_space() > 0) {
        if (_sender.segments_out().empty()) {
            send_empty = true;
        }
    }

    // !判断状态，进行回应
    // 1、listen
    // 2、收到syn
    // 3、主动发送syn
    // 4、主动发送fin或先接收到fin
    // 5、处理连接过程中的收到的数据
    // 5.1、纯ack包
    // 5.2、带负载的包
    // if (_sender.next_seqno_absolute() == 0 && !_receiver.ackno().has_value()) {
    //    return;
    //} else if (_sender.next_seqno_absolute() == 0 && header.syn) {
    //    connect();
    //} else if (header.syn) {
    //    send_empty = true;
    //} else if (_sender.stream_in().input_ended() || _receiver.stream_out().input_ended()) {
    //    if (ack_valid && (receive_valid || header.fin)) {
    //        send_empty = true;
    //    }
    //} else if (seg.payload().size() == 0) {
    //    if (!ack_valid) {
    //        send_empty = true;
    //    } else {
    //        _sender.fill_window();
    //    }
    //} else if (seg.payload().size() != 0) {
    //    if (_sender.stream_in().buffer_empty()) {
    //        send_empty = true;
    //    } else {
    //        _sender.fill_window();
    //    }
    //}

    if (header.fin && !_sender.stream_in().input_ended())
        _linger_after_streams_finish = false;

    if (send_empty) {
        _sender.send_empty_segment();
    }
    fill_segments_out();
}

bool TCPConnection::active() const {
    // unclean shutdown
    if (_receiver.stream_out().error() || _sender.stream_in().error()) {
        return false;
    };

    // clean shutdown
    if (unassembled_bytes() == 0 && _receiver.stream_out().eof() && _sender.bytes_in_flight() == 0 &&
        _sender.stream_in().eof()) {
        {
            if (_linger_after_streams_finish == false || time_since_last_segment_received() >= 10 * _cfg.rt_timeout)
                return false;
        }
    }
    return true;
}

size_t TCPConnection::write(const string &data) {
    if (!data.size()) {
        return 0;
    }
    size_t num_written = _sender.stream_in().write(data);
    _sender.fill_window();
    fill_segments_out();
    return num_written;
}

//! \param[in] ms_since_last_tick number of milliseconds since the last call to this method
void TCPConnection::tick(const size_t ms_since_last_tick) {
    _time_since_last_segment_received += ms_since_last_tick;
    _sender.tick(ms_since_last_tick);
    if (_sender.consecutive_retransmissions() > TCPConfig::MAX_RETX_ATTEMPTS) {
        reset();
        return;
    }
    if (_time_since_last_segment_received >= 10 * _cfg.rt_timeout && !active()) {
        _linger_after_streams_finish = false;
    }
    // this sentence has fooled me for several days, but i don't know the reason!!!
    // if (state() == TCPState::State::CLOSING || state() == TCPState::State::TIME_WAIT) {
    //_sender.send_empty_segment();
    fill_segments_out();
    //}
}

void TCPConnection::end_input_stream() {
    _sender.stream_in().end_input();
    _sender.fill_window();
    fill_segments_out();
}

void TCPConnection::connect() {
    _sender.fill_window();
    fill_segments_out();
}

void TCPConnection::fill_segments_out() {
    while (!_sender.segments_out().empty()) {
        TCPSegment segment = _sender.segments_out().front();
        _sender.segments_out().pop();
        if (_receiver.ackno().has_value()) {
            segment.header().ackno = _receiver.ackno().value();
            segment.header().ack = true;
        }
        segment.header().win = _receiver.window_size();
        _segments_out.push(segment);
    }
}

void TCPConnection::reset() {
    _receiver.stream_out().set_error();
    _sender.stream_in().set_error();
    _sender.send_empty_segment();
    TCPSegment segment = _sender.segments_out().front();
    _sender.segments_out().pop();
    segment.header().rst = true;
    _segments_out.push(segment);
}

TCPConnection::~TCPConnection() {
    try {
        if (active()) {
            cerr << "Warning: Unclean shutdown of TCPConnection\n";

            // Your code here: need to send a RST segment to the peer
            reset();
        }
    } catch (const exception &e) {
        std::cerr << "Exception destructing TCP FSM: " << e.what() << std::endl;
    }
}
